package com.solidsnake.scala.image

import java.io.File
import javax.imageio.ImageIO
import java.awt.image.BufferedImage
import scala.collection._
import java.awt.Color


/**
 * Created with IntelliJ IDEA.
 * User: Solidsnake
 * Date: 13-11-12
 * Time: 下午10:29
 * To change this template use File | Settings | File Templates.
 */
object CalculateImageDataManager {

  val path = System.getProperty("user.dir") + "/criteria"
  val criteriaImageSign = this.getCriteriaImageSign
  def getCriteriaImage = {
    val criteriaImage = mutable.Map[String, BufferedImage]()
    val directory = new File(path)
    directory.listFiles.foreach(imageFile => {
      criteriaImage.put(imageFile.getName, ImageIO.read(imageFile))
    })
    criteriaImage
  }

  /**
   *  获得标准图片（字模）特征码
   * @return
   */
  def getCriteriaImageSign = {
    /**
         *  读取图片特征吗
         * @param image
         * @return
         */
    def readImageSign(image : BufferedImage) = {
      val sign = new StringBuilder()
      for(x <- 0 to image.getWidth - 1; y <- 0 to image.getHeight - 1) {
        image.getRGB(x, y) match {
          case rgb if isSign(rgb) => sign append "1"
          case rgb if isImpurity(rgb) => sign append "0"
          case _ => sign append "?"
        }
      }

      /**
             *  是否是杂质
             * @param rgb
             * @return
             */
      def isImpurity(rgb : Int) = rgb == Color.WHITE.getRGB
      /**
             *  是否为特征码
             * @param rgb
             * @return
             */
      def isSign(rgb : Int) = {
        val color = new Color(rgb)
        val flags = (color.getRed <= 10) ::
          (color.getBlue <= 10) ::
          (color.getGreen <= 10) :: Nil
        flags.filter(_ == true).length == 3

      }

      sign.toString
    };

    def run = {
      var criteriaImageSign = List[DataModel]()
      this.getCriteriaImage.foreach({case(k, v) =>
        criteriaImageSign = new DataModel(k, v.getWidth, v.getHeight, readImageSign(v)) :: criteriaImageSign
      })
      criteriaImageSign
    };

    run
  }




  /**
     *  计算函数
     * @param image 要进行计算的图片
     * @param beginY Y轴的开始位置， 有些位置不固定， 完全扫描的话， 准确率比较低， 效率比较慢
     * @return
     */
  def calculate(image : BufferedImage, beginY : Array[Int] = Array(14, 17)) : List[String] = {




    /**
         *  获得首个字符位置
         * @return
         */
    def firstDataIndex = {
      var data = ""
      for(x <- 0 to image.getWidth - 1; y <- 0 to image.getHeight - 1) {
          // X点进行每个字模对比， 得出结果， 并获得一个验证码开始字符的的值
        if(image.getRGB(x, y) == Color.BLACK.getRGB && data.size != x + 1 ) {
          data += "1"
        }else if(y == image.getHeight - 1 && data.size != x + 1) {
          data += "0"
        }
      }
      data.indexOf("111") //返回匹配的第一个验证码字符位置（3个1的标识有3列都有黑点占据， 一般情况下不会出错， 但不排除特殊情况）
    };

    /**
         *  计算字模相似度
         * @return
         */
    def calculateModelSimilarity = {

      /**
             * 对比相似读
             * @param image
             * @param dataModel
             * @param beginX
             * @return
             */
      def compareSimilarity(image : BufferedImage, dataModel : DataModel, beginX : Int) : DataModel = {
        if(image.getWidth < beginX + dataModel.width) {
          dataModel.caseTraitCount = 0
          return dataModel
        }

        //  循环多个Y开始点位
        var counts : List[DataModel] = Nil
        val dataModelTraitCode = dataModel.traitCode.toCharArray

        beginY.foreach(v => {
          var index = 0
          val targetModel = new DataModel(dataModel.name, dataModel.width, dataModel.height, dataModel.traitCode)
          for(x <- beginX to beginX + dataModel.width - 1; y <- v - dataModel.height + 1 to v) {
            val pixelTraitCode = image.getRGB(x, y) match {
              case rgb if rgb == Color.BLACK.getRGB => "1"
              case rgb if rgb == Color.WHITE.getRGB => "0"
              case _ => "?"
            }
            if(pixelTraitCode.toCharArray()(0) == dataModelTraitCode(index)) {
              pixelTraitCode match {
                case "1" => targetModel.caseTraitCount += 1
                case "0" => targetModel.caseBackCount += 1
              }
            }
            index += 1

          }
          counts = targetModel :: counts
        });

        val highestModel = counts.sortWith(_.percentageSimilarity > _.percentageSimilarity).head
        highestModel
      };


      def run = {
        val map = mutable.Map[Int, List[DataModel]]()
        for(x <- firstDataIndex to image.getWidth -1) {
          val allCriteriaModel = criteriaImageSign.flatMap(v=> {
            compareSimilarity(image, v, x) :: Nil
          })
          map.put(x, allCriteriaModel)
        }
        map
      }

      run
    };

    /**
     *  计算最大相似读模型
     * @param func
     * @return
     */
    def calculateMaxSimilarityModel(func : () => Map[Int, List[DataModel]]) : List[String] = {

      val sb = func()
      var index = firstDataIndex
      var maxSimilarityModels : List[String] = Nil
      while(index != -1){
        index =
          //需要修改为 符合的特征码+ 符合的背景 的百分比
          if(sb(index + 2).sortWith(_.percentageSimilarity > _.percentageSimilarity).head.percentageSimilarity != 0) {
            val filterRange : Map[Int, List[DataModel]] = sb.filter({case (k,v) => k >= index - 2 && k <= index + 2})
            val rangeMaxModelGroup = filterRange.maxBy({case (k, v) => {
              v.sortWith(_.percentageSimilarity > _.percentageSimilarity).head.percentageSimilarity
            }})
            val rangeMaxTargetDataModel = rangeMaxModelGroup._2.sortWith(_.percentageSimilarity > _.percentageSimilarity).head
            maxSimilarityModels = rangeMaxTargetDataModel.name.substring(1,2) :: maxSimilarityModels
            rangeMaxModelGroup._1 + rangeMaxTargetDataModel.width
          }else {
            -1
          }
      }
      return maxSimilarityModels.reverse
    };


    var result : List[String] = Nil
    try {
      result = calculateMaxSimilarityModel(calculateModelSimilarity _)
    } catch {
      case e: Exception => println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EXCEPTION!!!!!!!!!!!!"); new RuntimeException(e)
    }
    return result
  }


  def readVerificationCode(path : String) : List[String]= {
    val image = ImageIO.read(new File(path));
    return this.readVerificationCode(image)
  }

  def readVerificationCode(images : BufferedImage) : List[String] = {
    val graying = ImageManage.graying(images)
    val image = ImageManage.changeImages(graying);
    val image2 = ImageManage.removeNoise(image);
    val image3 = ImageManage.repairImage(image2)
    return CalculateImageDataManager.calculate(image3)
  }

  def main(arg : Array[String]) = {

    val paths = System.getProperty("user.dir")
    val graying = ImageManage.graying(paths + "/62jt6.gif")
    ImageIO.write(graying, "bmp", new File(paths + "/temp/_graying.bmp"));
    val image = ImageManage.changeImages(paths + "/temp/_graying.bmp");
    ImageIO.write(image, "bmp", new File(paths + "/temp/_0.bmp"));

    val image2 = ImageManage.removeNoise(paths + "/temp/_0.bmp");
    ImageIO.write(image2, "bmp", new File(paths + "/temp/_A.bmp"));
    val image3 = ImageManage.repairImage(image2)
    ImageIO.write(image3, "bmp", new File(paths + "/temp/_B.bmp"));
    this.calculate(image3)
  }

} 
